import { Storage, STORAGE_KEYS } from './storage'

// 错误类型枚举
export enum ErrorType {
  NETWORK = 'NETWORK',
  API = 'API',
  VALIDATION = 'VALIDATION',
  PERMISSION = 'PERMISSION',
  SYSTEM = 'SYSTEM',
  UNKNOWN = 'UNKNOWN',
}

// 错误信息接口
export interface ErrorInfo {
  type: ErrorType
  message: string
  code?: string | number
  stack?: string
  timestamp: number
  url?: string
  userAgent?: string
  userId?: string
  extra?: Record<string, any>
}

// 错误上报配置
interface ErrorReportConfig {
  enabled: boolean
  url: string
  batchSize: number
  maxRetries: number
  timeout: number
}

// 错误管理器类
class ErrorManager {
  private errors: ErrorInfo[] = []
  private config: ErrorReportConfig = {
    enabled: true,
    url: 'https://api.example.com/error-report',
    batchSize: 10,
    maxRetries: 3,
    timeout: 5000,
  }

  constructor() {
    this.init()
  }

  // 初始化错误处理
  private init(): void {
    // 监听全局错误
    this.setupGlobalErrorHandler()

    // 监听未处理的 Promise 拒绝
    this.setupUnhandledRejectionHandler()

    // 定期上报错误
    this.setupErrorReport()
  }

  // 设置全局错误处理器
  private setupGlobalErrorHandler(): void {
    // 监听 JavaScript 错误
    // #ifdef H5
    window.addEventListener('error', (event) => {
      this.handleError({
        type: ErrorType.SYSTEM,
        message: event.message || 'Unknown error',
        code: 'JS_ERROR',
        stack: event.error?.stack,
        timestamp: Date.now(),
        url: event.filename,
        userAgent: navigator.userAgent,
      })
    })
    // #endif

    // 监听资源加载错误
    // #ifdef H5
    window.addEventListener('unhandledrejection', (event) => {
      this.handleError({
        type: ErrorType.SYSTEM,
        message: event.reason?.message || 'Unhandled promise rejection',
        code: 'PROMISE_REJECTION',
        stack: event.reason?.stack,
        timestamp: Date.now(),
        url: window.location.href,
        userAgent: navigator.userAgent,
      })
    })
    // #endif
  }

  // 设置未处理的 Promise 拒绝处理器
  private setupUnhandledRejectionHandler(): void {
    // #ifdef H5
    window.addEventListener('unhandledrejection', (event) => {
      this.handleError({
        type: ErrorType.SYSTEM,
        message: event.reason?.message || 'Unhandled promise rejection',
        code: 'PROMISE_REJECTION',
        stack: event.reason?.stack,
        timestamp: Date.now(),
        url: window.location.href,
        userAgent: navigator.userAgent,
      })
    })
    // #endif
  }

  // 设置错误上报定时器
  private setupErrorReport(): void {
    // 每30秒检查一次是否有待上报的错误
    setInterval(() => {
      if (this.errors.length >= this.config.batchSize) {
        this.reportErrors()
      }
    }, 30000)
  }

  // 处理错误
  handleError(errorInfo: ErrorInfo): void {
    // 添加用户信息
    const userInfo = Storage.get(STORAGE_KEYS.USER_INFO)
    if (userInfo) {
      errorInfo.userId = userInfo.id?.toString()
    }

    // 添加到错误列表
    this.errors.push(errorInfo)

    // 控制台输出
    console.error('Error captured:', errorInfo)

    // 立即上报严重错误
    if (this.isCriticalError(errorInfo)) {
      this.reportErrors()
    }

    // 显示用户友好的错误信息
    this.showUserFriendlyError(errorInfo)
  }

  // 判断是否为严重错误
  private isCriticalError(errorInfo: ErrorInfo): boolean {
    const criticalTypes = [ErrorType.SYSTEM, ErrorType.PERMISSION]
    const criticalCodes = ['JS_ERROR', 'PROMISE_REJECTION']

    return (
      criticalTypes.includes(errorInfo.type) ||
      criticalCodes.includes(errorInfo.code as string) ||
      errorInfo.message.includes('Cannot read property') ||
      errorInfo.message.includes('Cannot read properties')
    )
  }

  // 显示用户友好的错误信息
  private showUserFriendlyError(errorInfo: ErrorInfo): void {
    let message = '系统异常，请稍后重试'

    switch (errorInfo.type) {
      case ErrorType.NETWORK:
        message = '网络连接失败，请检查网络设置'
        break
      case ErrorType.API:
        message = errorInfo.message || '请求失败，请稍后重试'
        break
      case ErrorType.VALIDATION:
        message = errorInfo.message || '输入信息有误，请检查后重试'
        break
      case ErrorType.PERMISSION:
        message = '没有访问权限，请联系管理员'
        break
      case ErrorType.SYSTEM:
        message = '系统异常，请刷新页面重试'
        break
    }

    uni.showToast({
      title: message,
      icon: 'none',
      duration: 3000,
    })
  }

  // 上报错误
  private async reportErrors(): Promise<void> {
    if (!this.config.enabled || this.errors.length === 0) {
      return
    }

    const errorsToReport = this.errors.splice(0, this.config.batchSize)

    try {
      await this.sendErrorReport(errorsToReport)
      console.log(`Successfully reported ${errorsToReport.length} errors`)
    } catch (error) {
      console.error('Failed to report errors:', error)
      // 将错误重新加入队列
      this.errors.unshift(...errorsToReport)
    }
  }

  // 发送错误报告
  private async sendErrorReport(errors: ErrorInfo[]): Promise<void> {
    return new Promise((resolve, reject) => {
      const timeout = setTimeout(() => {
        reject(new Error('Error report timeout'))
      }, this.config.timeout)

      uni.request({
        url: this.config.url,
        method: 'POST',
        data: {
          errors,
          appVersion: '1.0.0', // 从配置中获取
          platform: this.getPlatform(),
          timestamp: Date.now(),
        },
        header: {
          'Content-Type': 'application/json',
        },
        success: () => {
          clearTimeout(timeout)
          resolve()
        },
        fail: (error: any) => {
          clearTimeout(timeout)
          reject(error)
        },
      })
    })
  }

  // 获取平台信息
  private getPlatform(): string {
    // #ifdef H5
    return 'H5'
    // #endif
    // #ifdef MP-WEIXIN
    return 'MP-WEIXIN'
    // #endif
    // #ifdef MP-ALIPAY
    return 'MP-ALIPAY'
    // #endif
    // #ifdef MP-BAIDU
    return 'MP-BAIDU'
    // #endif
    // #ifdef MP-TOUTIAO
    return 'MP-TOUTIAO'
    // #endif
    // #ifdef APP-PLUS
    return 'APP-PLUS'
    // #endif
    return 'UNKNOWN'
  }

  // 创建错误信息
  createError(
    type: ErrorType,
    message: string,
    code?: string | number,
    extra?: Record<string, any>
  ): ErrorInfo {
    return {
      type,
      message,
      code,
      timestamp: Date.now(),
      url: this.getCurrentUrl(),
      userAgent: this.getUserAgent(),
      extra,
    }
  }

  // 获取当前URL
  private getCurrentUrl(): string {
    // #ifdef H5
    return window.location.href
    // #endif
    // #ifdef MP-WEIXIN || MP-ALIPAY || MP-BAIDU || MP-TOUTIAO
    if (typeof (globalThis as any).getCurrentPages === 'function') {
      const pages = (globalThis as any).getCurrentPages()
      return pages.length > 0 ? `/${pages[pages.length - 1].route}` : ''
    }
    // #endif
    return ''
  }

  // 获取用户代理
  private getUserAgent(): string {
    // #ifdef H5
    return navigator.userAgent
    // #endif
    return ''
  }

  // 手动上报错误
  reportError(errorInfo: ErrorInfo): void {
    this.handleError(errorInfo)
  }

  // 清空错误队列
  clearErrors(): void {
    this.errors = []
  }

  // 获取错误统计
  getErrorStats(): { total: number; byType: Record<string, number> } {
    const byType: Record<string, number> = {}

    this.errors.forEach((error) => {
      byType[error.type] = (byType[error.type] || 0) + 1
    })

    return {
      total: this.errors.length,
      byType,
    }
  }

  // 更新配置
  updateConfig(config: Partial<ErrorReportConfig>): void {
    this.config = { ...this.config, ...config }
  }
}

// 创建错误管理器实例
export const errorManager = new ErrorManager()

// 便捷方法
export const handleError = errorManager.handleError.bind(errorManager)
export const createError = errorManager.createError.bind(errorManager)
export const reportError = errorManager.reportError.bind(errorManager)

// 错误边界组件（用于页面级错误捕获）
export const withErrorBoundary = (component: any) => {
  return {
    ...component,
    onError(error: any) {
      errorManager.handleError({
        type: ErrorType.SYSTEM,
        message: error.message || 'Component error',
        code: 'COMPONENT_ERROR',
        stack: error.stack,
        timestamp: Date.now(),
        url: this.getCurrentUrl?.() || '',
        userAgent: this.getUserAgent?.() || '',
      })
    },
  }
}

export default errorManager
